﻿// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;

using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Project.Converter;
using ICSharpCode.SharpDevelop.Util;

namespace ICSharpCode.SharpDevelop.Project
{
	/// <summary>
	/// A compilable project based on MSBuild.
	/// </summary>
	public abstract class ValidationProject : MSBuildBasedProject
	{
		#region Static methods
		/// <summary>
		/// Gets the file extension of the assembly created when building a project
		/// with the specified output type.
		/// Example: OutputType.Exe => ".exe"
		/// </summary>
		public static string GetExtension(OutputType outputType)
		{
			switch (outputType) {
				case OutputType.WinExe:
				case OutputType.Exe:
					return ".exe";
				case OutputType.Module:
					return ".netmodule";
				default:
					return ".dll";
			}
		}
		#endregion
		
		/// <summary>
		/// A list of project properties that cause reparsing of references when they are changed.
		/// </summary>
		protected readonly ISet<string> reparseReferencesSensitiveProperties = new SortedSet<string>();
		
		/// <summary>
		/// A list of project properties that cause reparsing of code when they are changed.
		/// </summary>
		protected readonly ISet<string> reparseCodeSensitiveProperties = new SortedSet<string>();
		
		protected ValidationProject(ICSharpCode.SharpDevelop.Internal.Templates.ProjectCreateInformation information)
			: base(information)
		{
			SetProperty("Debug", null, "OutputPath", @"bin\Debug\",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			SetProperty("Release", null, "OutputPath", @"bin\Release\",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			InvalidateConfigurationPlatformNames();
			
			SetProperty("Debug", null, "DebugSymbols", "True",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			SetProperty("Release", null, "DebugSymbols", "False",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			
			SetProperty("Debug", null, "DebugType", "Full",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			SetProperty("Release", null, "DebugType", "None",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			
			SetProperty("Debug", null, "Optimize", "False",
			            PropertyStorageLocations.ConfigurationSpecific, true);
			SetProperty("Release", null, "Optimize", "True",
			            PropertyStorageLocations.ConfigurationSpecific, true);
		}

        protected ValidationProject(ProjectLoadInformation information)
			: base(information)
		{
		}
		
		// Make Language abstract again to ensure backend-binding implementers don't forget
		// to set it.
		public abstract override string Language {
			get;
		}
		
		public abstract override ICSharpCode.SharpDevelop.Dom.LanguageProperties LanguageProperties {
			get;
		}
		
		/// <summary>
		/// The full path of the folder where the project's primary output files go.
		/// </summary>
		public string OutputFullPath {
			get {
				string outputPath = GetEvaluatedProperty("OutputPath");
				// FileUtility.NormalizePath() cleans up any back references.
				// e.g. C:\windows\system32\..\system becomes C:\windows\system
				return FileUtility.NormalizePath(Path.Combine(Directory, outputPath));
			}
		}
		
		protected override ParseProjectContent CreateProjectContent()
		{
			ParseProjectContent newProjectContent = new ParseProjectContent(this);
			return newProjectContent;
		}
		
		protected override void OnActiveConfigurationChanged(EventArgs e)
		{
			base.OnActiveConfigurationChanged(e);
			if (!isLoading) {
				ParserService.Reparse(this, true, true);
			}
		}
		
		protected override void OnPropertyChanged(ProjectPropertyChangedEventArgs e)
		{
			base.OnPropertyChanged(e);
            if (e.PropertyName == "TargetFrameworkVersion")
                CreateItemsListFromMSBuild();
			if (!isLoading) {
				if (reparseReferencesSensitiveProperties.Contains(e.PropertyName)) {
					ParserService.Reparse(this, true, false);
				}
				if (reparseCodeSensitiveProperties.Contains(e.PropertyName)) {
					ParserService.Reparse(this, false, true);
				}
			}
		}
		
		[Browsable(false)]
		public override string TypeGuid {
			get {
				return ProjectBindingService.GetCodonPerLanguageName(Language).Guid;
			}
			set {
				throw new NotSupportedException();
			}
		}
		
		public StartAction StartAction {
			get {
				try {
					return (StartAction)Enum.Parse(typeof(StartAction), GetEvaluatedProperty("StartAction") ?? "Project");
				} catch (ArgumentException) {
					return StartAction.Project;
				}
			}
			set {
				SetProperty("StartAction", value.ToString());
			}
		}

        protected override ProjectBehavior CreateDefaultBehavior()
        {
            return new DefaultProjectBehavior(this);
        }
		
		#region IUpgradableProject
        //[Browsable(false)]
        //public virtual bool UpgradeDesired {
        //    get {
        //        return MinimumSolutionVersion < Solution.SolutionVersionVS2010;
        //    }
        //}
		
        //public virtual CompilerVersion CurrentCompilerVersion {
        //    get { return GetOrCreateBehavior().CurrentCompilerVersion; }
        //}
		
        //public virtual TargetFramework CurrentTargetFramework {
        //    get { return GetOrCreateBehavior().CurrentTargetFramework; }
        //}
		
        //public virtual IEnumerable<CompilerVersion> GetAvailableCompilerVersions()
        //{
        //    return GetOrCreateBehavior().GetAvailableCompilerVersions();
        //}
		
        //public virtual IEnumerable<TargetFramework> GetAvailableTargetFrameworks()
        //{
        //    return GetOrCreateBehavior().GetAvailableTargetFrameworks();
        //}
		
        //public virtual void UpgradeProject(CompilerVersion newVersion, TargetFramework newFramework)
        //{
        //    if (!ReadOnly)
        //        GetOrCreateBehavior().UpgradeProject(newVersion, newFramework);
        //}
		
		#endregion
	}
}
